package auth

import (
	"github.com/gin-gonic/gin"
	"github.com/lab-online/pkg/jwt"
	"github.com/lab-online/pkg/resp"
)

type Role uint8

const (
	RoleStudent Role = 1 << iota
	RoleTeacher
	RoleAdmin
	RoleAll = RoleStudent | RoleTeacher | RoleAdmin

	KeyAuth = "auth"
)

type Auth struct {
	Username string
	Role     Role
}

type TokenParser interface {
	ParseToken(token string) (*jwt.Claims, error)
}

type Middleware func(Role) gin.HandlerFunc

func New(parser TokenParser) Middleware {
	return func(enabled Role) gin.HandlerFunc {
		return func(c *gin.Context) {
			bearerToken := c.GetHeader("Authorization")
			if claims, err := parseBearerToken(bearerToken, parser); err != nil {
				c.Error(err)
				resp.ErrorHandler(c, err)
			} else if enabled&Role(claims.Role) != 0 {
				c.Set(KeyAuth, &Auth{claims.Username, Role(claims.Role)})
				c.Next()
			} else {
				c.Error(resp.RESTErrForbidden)
				resp.ErrorHandler(c, resp.RESTErrForbidden)
				return
			}
		}
	}
}

func parseBearerToken(bearerToken string, parser TokenParser) (*jwt.Claims, error) {
	if len(bearerToken) <= 7 {
		return nil, resp.RESTErrBearerTokenErr
	} else if claims, err := parser.ParseToken(bearerToken[7:]); err != nil {
		return nil, resp.RESTErrAuth
	} else {
		return claims, nil
	}
}
